package com.hqyj.springCloudWeb.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author yun
 * @date 2021-5-6 22:56
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private MyRealm myRealm;

    //管理Shiro组件的方法
    @Bean//将方法注册到ioc容器中
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置Shiro核心组件
        securityManager.setRealm(myRealm);
        //设置记住我组件
        securityManager.setRememberMeManager(rememberMeManager());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * -配置 shiro 过滤器工厂
     * -----------------
     * -拦截权限
     * anon：匿名访问，无需登录
     * authc：登录后才能访问 ---- FormAuthenticationFilter
     * user：登录过能访问 ---- UserFilter
     * logout：登出 ---- LogoutFilter
     * roles：角色过滤器
     * ------------------
     * URL匹配风格
     * ?：匹配一个字符，如 /admin? 将匹配 /admin1，但不匹配 /admin 或 /admin/
     * *：匹配零个或多个字符串，如 /admin* 将匹配 /admin 或/admin123，但不匹配 /admin/1
     * **：匹配路径中的零个或多个路径，如 /admin/** 将匹配 /admin/a 或 /admin/a/b
     * -----------------------
     * -方法名不能乱写，如果我们定义为别的名称，又没有添加注册过滤器的配置，
     * -那么 shiro 会加载 ShiroWebFilterConfiguration 过滤器，
     * -该过滤器会寻找 shiroFilterFactoryBean，找不到会抛出异常
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //将我们设置好的安全管理器（MyRealm）加入访问策略(过滤器)中
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/common/dashboard");

        // 添加访问策略。第一个string是路径的表达式，第二个是所选择的策略
        Map<String, String> map = new LinkedHashMap<>();
        //匿名访问策略（不需要登录就能访问的）
        map.put("/vendors/**","anon");
        map.put("/css/**","anon");
        map.put("/js/**","anon");
        map.put("/images/**","anon");
        //本地资源
        map.put("/image/**","anon");
        map.put("/login","anon");
        map.put("/register","anon");
        map.put("/api/**","anon");

        //登录过的访问策略
        map.put("/**","user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    /**
     * - 注册shiro方言，让 thymeleaf 支持 shiro 标签
     */
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    /**
     * DefaultAdvisorAutoProxyCreator, Advisor 代理类生成器
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * - 创建 AuthorizationAttributeSourceAdvisor，扫描 Shiro 注解
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * -- Remember Me Cookie
     */
    @Bean
    public SimpleCookie rememberMeCookie() {
        // 这个参数是 cookie 的名称
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //如果 httyOnly 设置为 true，则客户端不会暴露给客户端脚本代码，
        //使用 HttpOnly cookie 有助于减少某些类型的跨站点脚本攻击；
        simpleCookie.setHttpOnly(true);
        //记住我 cookie 生效时间,单位是秒
        simpleCookie.setMaxAge(1 * 24 * 60 * 60);
        return simpleCookie;
    }

    /**
     * -- 记住我管理器
     */
    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //加密的数组
        byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");
        cookieRememberMeManager.setCipherService(new AesCipherService());
        cookieRememberMeManager.setCipherKey(cipherKey);
        return cookieRememberMeManager;
    }

    @Bean
    public SimpleCookie sessionCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("shiro.sesssion");
        simpleCookie.setPath("/");
        simpleCookie.setHttpOnly(true);
        simpleCookie.setMaxAge(1 * 24 * 60 * 60);
        return simpleCookie;
    }

    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionIdCookie(sessionCookie());
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionValidationInterval(1 * 24 * 60 * 60 * 1000);
        sessionManager.setGlobalSessionTimeout(1 * 24 * 60 * 60 * 1000);
        return sessionManager;
    }
}
